/*
 * Copyright (c) 2018. 玺得（深圳）科技有限公司.保留所有权利. http://www.pi-top.com/ 玺得（深圳）科技有限公司保留所有代码著作权.如有任何疑问请访问官方网站与我们联系. 代码只针对特定需求定制编码，不得在未经允许或授权的情况下对外传播扩散.恶意传播者，法律后果自行承担. 本代码仅用于pps-cloud系统.
 */
package com.pitop.sync.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baidu.fsg.uid.UidGenerator;
import com.pitop.core.base.BaseDAO;
import com.pitop.core.base.BaseSVImpl;
import com.pitop.core.entity.BeanRet;
import com.pitop.core.entity.Page;
import com.pitop.core.exceptions.BaseException;
import com.pitop.core.exceptions.SyncNewDataException;
import com.pitop.core.tools.security.Md5;
import com.pitop.errortype.service.ErrortypeSV;
import com.pitop.sample.service.SampleSV;
import com.pitop.serial.service.SerialNumberTemplateSV;
import com.pitop.staff.service.StaffSV;
import com.pitop.sync.dao.SyncNewDataDAO;
import com.pitop.sync.entity.SyncNewData;
import com.pitop.sync.entity.SyncNewDataState;
import com.pitop.sync.entity.SyncTraceModel;
import com.pitop.sync.entity.SyncTraceState;
import com.pitop.test.service.TestOptionSV;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;

import javax.annotation.Resource;
import java.util.*;

@Service("syncNewDataSV")
@Slf4j
public class SyncNewDataSVImpl extends BaseSVImpl<SyncNewData, Long> implements SyncNewDataSV {

    @Autowired
    private SyncNewDataDAO syncNewDataDAO;

    @Autowired
    private StaffSV staffSV;

    @Autowired
    private TestOptionSV testOptionSV;

    @Autowired
    private SampleSV sampleSV;

    @Autowired
    private ErrortypeSV errortypeSV;

    @Autowired
    private SerialNumberTemplateSV serialNumberTemplateSV;

    @Autowired
    private SyncDataTraceSV syncDataTraceSV;

    @Autowired
    private SyncTraceSV syncTraceSV;


    @Resource
    private UidGenerator uidGenerator;

    @Override
    protected BaseDAO getBaseDAO() {
        return syncNewDataDAO;
    }

    /**
     * 保存account对象
     *
     * @param entity 实体
     * @throws BaseException
     */
    @Override
    public void save(SyncNewData entity) throws BaseException {
        entity.setCode(String.valueOf(uidGenerator.getUID()));
        entity.setCreateTime(new Date());
        entity.setUpdateTime(new Date());
        super.save(entity);
    }

    /**
     * 保存需要同步的数据
     *
     * @param factoryCode
     * @param model
     * @param event
     * @param dataCode
     * @param ver
     * @param state
     */
    @Override
    public void save(String factoryCode, String model, String event, String dataCode, int ver, String state) {
        SyncNewData syncNewData = new SyncNewData();
        syncNewData.setCode(String.valueOf(uidGenerator.getUID()));
        syncNewData.setFactoryCode(factoryCode);
        syncNewData.setModel(model);
        syncNewData.setEvent(event);
        syncNewData.setDataCode(dataCode);
        syncNewData.setVer(ver);
        syncNewData.setState(state);
        syncNewData.setCreateTime(new Date());
        syncNewData.setUpdateTime(new Date());
        super.save(syncNewData);
    }

    /**
     * 加载一个对象SyncNewData
     *
     * @param id id* @param code 编码* @param factoryCode 工厂编码* @param dataCode 数据编码
     * @return SyncNewData
     */
    @Override
    public SyncNewData load(java.lang.Long id, java.lang.String code, java.lang.String factoryCode, java.lang.String dataCode) {
        if (id == null && code == null && factoryCode == null && dataCode == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }

        Map<String, Object> param = new HashMap<>();
        param.put("id", id);
        param.put("code", code);
        param.put("factoryCode", factoryCode);
        param.put("dataCode", dataCode);
        return syncNewDataDAO.load(param);
    }

    /**
     * 加载一个对象SyncNewData 通过id
     *
     * @param id id
     * @return SyncNewData
     */
    @Override
    public SyncNewData loadById(java.lang.Long id) {
        if (id == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        return syncNewDataDAO.loadById(id);
    }

    /**
     * 加载一个对象SyncNewData 通过code
     *
     * @param code 编码
     * @return SyncNewData
     */
    @Override
    public SyncNewData loadByCode(java.lang.String code) {
        if (code == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        return syncNewDataDAO.loadByCode(code);
    }

    /**
     * 加载一个对象SyncNewData 通过factoryCode
     *
     * @param factoryCode 工厂编码
     * @return SyncNewData
     */
    @Override
    public List<SyncNewData> listByFactoryCode(java.lang.String factoryCode) {
        if (factoryCode == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        return syncNewDataDAO.listByFactoryCode(factoryCode);
    }

    /**
     * 加载一个对象SyncNewData 通过dataCode
     *
     * @param dataCode 数据编码
     * @return SyncNewData
     */
    @Override
    public List<SyncNewData> listByDataCode(java.lang.String dataCode) {
        if (dataCode == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        return syncNewDataDAO.listByDataCode(dataCode);
    }


    /**
     * 根据主键id,oldStates 共同更新 SyncNewData 的状态到newState状态
     *
     * @param id        id
     * @param newState  新状态
     * @param oldStates 旧状态集合
     */
    @Override
    public void updateStateById(java.lang.Long id, SyncNewDataState newState, SyncNewDataState... oldStates) {
        if (id == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        if (newState == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        if (oldStates == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        String[] states = new String[oldStates.length];
        for (int i = 0; i < oldStates.length; i++) {
            states[i] = oldStates[i].name();
        }
        syncNewDataDAO.updateStateById(id, newState.name(), states);
    }

    /**
     * 根据主键code,oldStates 共同更新 SyncNewData 的状态到newState状态
     *
     * @param code      编码
     * @param newState  新状态
     * @param oldStates 旧状态集合
     */
    @Override
    public void updateStateByCode(java.lang.String code, SyncNewDataState newState, SyncNewDataState... oldStates) {
        if (code == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        if (newState == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        if (oldStates == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        String[] states = new String[oldStates.length];
        for (int i = 0; i < oldStates.length; i++) {
            states[i] = oldStates[i].name();
        }
        syncNewDataDAO.updateStateByCode(code, newState.name(), states);
    }

    /**
     * 根据主键factoryCode,oldStates 共同更新 SyncNewData 的状态到newState状态
     *
     * @param factoryCode 工厂编码
     * @param newState    新状态
     * @param oldStates   旧状态集合
     */
    @Override
    public void updateStateByFactoryCode(java.lang.String factoryCode, SyncNewDataState newState, SyncNewDataState... oldStates) {
        if (factoryCode == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        if (newState == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        if (oldStates == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        String[] states = new String[oldStates.length];
        for (int i = 0; i < oldStates.length; i++) {
            states[i] = oldStates[i].name();
        }
        syncNewDataDAO.updateStateByFactoryCode(factoryCode, newState.name(), states);
    }

    /**
     * 根据主键dataCode,oldStates 共同更新 SyncNewData 的状态到newState状态
     *
     * @param dataCode  数据编码
     * @param newState  新状态
     * @param oldStates 旧状态集合
     */
    @Override
    public void updateStateByDataCode(java.lang.String dataCode, SyncNewDataState newState, SyncNewDataState... oldStates) {
        if (dataCode == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        if (newState == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        if (oldStates == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        String[] states = new String[oldStates.length];
        for (int i = 0; i < oldStates.length; i++) {
            states[i] = oldStates[i].name();
        }
        syncNewDataDAO.updateStateByDataCode(dataCode, newState.name(), states);
    }

    /**
     * 根据主键id 更新 SyncNewData 的状态到另一个状态
     *
     * @param id    id
     * @param state 状态
     */
    @Override
    public void updateById(java.lang.Long id, SyncNewDataState state) {
        if (id == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        syncNewDataDAO.updateById(id, state.name());
    }

    /**
     * 根据主键code 更新 SyncNewData 的状态到另一个状态
     *
     * @param code  编码
     * @param state 状态
     */
    @Override
    public void updateByCode(java.lang.String code, SyncNewDataState state) {
        if (code == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        syncNewDataDAO.updateByCode(code, state.name());
    }

    /**
     * 根据主键factoryCode 更新 SyncNewData 的状态到另一个状态
     *
     * @param factoryCode 工厂编码
     * @param state       状态
     */
    @Override
    public void updateByFactoryCode(java.lang.String factoryCode, SyncNewDataState state) {
        if (factoryCode == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        syncNewDataDAO.updateByFactoryCode(factoryCode, state.name());
    }

    /**
     * 根据主键dataCode 更新 SyncNewData 的状态到另一个状态
     *
     * @param dataCode 数据编码
     * @param state    状态
     */
    @Override
    public void updateByDataCode(java.lang.String dataCode, SyncNewDataState state) {
        if (dataCode == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        syncNewDataDAO.updateByDataCode(dataCode, state.name());
    }


    /**
     * 删除对象SyncNewData
     *
     * @param id id* @param code 编码* @param factoryCode 工厂编码* @param dataCode 数据编码
     * @return SyncNewData
     */
    @Override
    public void delete(java.lang.Long id, java.lang.String code, java.lang.String factoryCode, java.lang.String dataCode) {
        if (id == null && code == null && factoryCode == null && dataCode == null) {
            throw new SyncNewDataException(BaseException.BaseExceptionEnum.Illegal_Param);
        }
        Map<String, Object> param = new HashMap<>();
        param.put("id", id);
        param.put("code", code);
        param.put("factoryCode", factoryCode);
        param.put("dataCode", dataCode);
        syncNewDataDAO.delete(param);
    }


    /**
     * 查询SyncNewData分页
     *
     * @param syncNewData 对象
     * @param offset      查询开始行
     * @param limit       查询行数
     * @return List<SyncNewData>
     */
    @Override
    public List<SyncNewData> list(SyncNewData syncNewData, int offset, int limit) {
        if (offset < 0) {
            offset = 0;
        }

        if (limit < 0) {
            limit = Page.limit;
        }

        Map<String, Object> map = null;
        if (syncNewData != null) {
            map = JSON.parseObject(JSON.toJSONString(syncNewData, SerializerFeature.WriteDateUseDateFormat));
        } else {
            map = new HashMap<>();
        }
        map.put("sortColumns", " code desc ");
        return syncNewDataDAO.list(map, new RowBounds(offset, limit));
    }

    @Override
    public int count(SyncNewData syncNewData) {
        Map<String, Object> map;
        if (syncNewData != null) {
            map = JSON.parseObject(JSON.toJSONString(syncNewData, SerializerFeature.WriteDateUseDateFormat));
        } else {
            map = new HashMap<>();
        }
        return syncNewDataDAO.count(map);
    }

    /**
     * 查询SyncNewData分页
     *
     * @param id     id* @param code  编码* @param factoryCode  工厂编码* @param dataCode  数据编码
     * @param offset 查询开始行
     * @param limit  查询行数
     * @return List<SyncNewData>
     */
    @Override
    public List<SyncNewData> list(java.lang.Long id, java.lang.String code, java.lang.String factoryCode, java.lang.String dataCode, int offset, int limit) {
        if (offset < 0) {
            offset = 0;
        }

        if (limit < 0) {
            limit = Page.limit;
        }
        Map<String, Object> param = new HashMap<>();
        param.put("id", id);
        param.put("code", code);
        param.put("factoryCode", factoryCode);
        param.put("dataCode", dataCode);
        return syncNewDataDAO.list(param, new RowBounds(offset, limit));
    }

    @Override
    public int count(java.lang.Long id, java.lang.String code, java.lang.String factoryCode, java.lang.String dataCode) {
        Map<String, Object> param = new HashMap<>();
        param.put("id", id);
        param.put("code", code);
        param.put("factoryCode", factoryCode);
        param.put("dataCode", dataCode);
        return syncNewDataDAO.count(param);
    }

    /**
     * 从云端往工厂端同步数据调度接口
     *
     * @param factoryCode 工厂Code
     * @param thresHold   超出阈值的最小时间(Date类型)
     * @return BeanRet
     */
    @Override
    public BeanRet syncDataToDown(String factoryCode, Date thresHold) {
        Map<String, Object> paraMap = new HashMap<>();
        List<String> paramList = new ArrayList();
        if (thresHold != null) {
            //阈值时间不为空,查询是否有状态为同步中且超出阈值的数据
            paramList.add(SyncNewDataState.Sync.name());
            paraMap.put("oldStates", paramList);
            paraMap.put("thresHold", thresHold);
        } else {
            paramList.add(SyncNewDataState.Ready.name());
            paramList.add(SyncNewDataState.Error.name());
            paraMap.put("oldStates", paramList);
        }
        paraMap.put("factoryCode", factoryCode);
        List<SyncNewData> syncNewDataList = syncNewDataDAO.syncDataToDown(paraMap);
        if (syncNewDataList != null && syncNewDataList.size() > 0) {
            if (thresHold != null) {
                //修改状态为错误就行了
                paraMap.put("state", SyncNewDataState.Error.name());
                paraMap.put("updateTime", new Date());
                syncNewDataDAO.updateByFactoryCodeAndState(paraMap);
                return BeanRet.create(true, "数据状态修改成功!");
            }
            for (int i = 0; i < syncNewDataList.size(); i++) {
                if (SyncTraceModel.Staff.name().equals(syncNewDataList.get(i).getModel())) {
                    //员工表
                    syncNewDataList.get(i).setStaff(staffSV.loadByCode(syncNewDataList.get(i).getDataCode()));
                } else if (SyncTraceModel.Sample.name().equals(syncNewDataList.get(i).getModel())) {
                    //样品表
                    syncNewDataList.get(i).setSample(sampleSV.loadByCode(syncNewDataList.get(i).getDataCode()));
                } else if (SyncTraceModel.Test_option.name().equals(syncNewDataList.get(i).getModel())) {
                    //样品测试项
                    syncNewDataList.get(i).setTestOption(testOptionSV.loadByCode(syncNewDataList.get(i).getDataCode()));
                } else if (SyncTraceModel.Serial_number_template.name().equals(syncNewDataList.get(i).getModel())) {
                    //序列号模板
                    syncNewDataList.get(i).setSerialNumberTemplate(serialNumberTemplateSV.loadByCode(syncNewDataList.get(i).getDataCode()));
                } else if (SyncTraceModel.Errortype.name().equals(syncNewDataList.get(i).getModel())) {
                    //错误类型
                    syncNewDataList.get(i).setErrortype(errortypeSV.loadByCode(syncNewDataList.get(i).getDataCode()));
                }
            }
            //HTTP远程调用PPS-factory接口,传递数据用于同步,数据同步之前,需要修改状态为同步中
            //数据同步前,更改状态为同步中
            paraMap.put("state", SyncNewDataState.Sync.name());
            paraMap.put("updateTime", new Date());
            syncNewDataDAO.updateByFactoryCodeAndState(paraMap);

            String json = JSON.toJSONString(syncNewDataList);
            String base64Json = Base64Utils.encodeToString(json.getBytes());
            return BeanRet.create(true, Md5.md5(json), (Object) base64Json);
        }
        return BeanRet.create(true, BaseException.BaseExceptionEnum.No_Data_To_Update);
    }


    /**
     * 更新同步数据状态
     *
     * @param syncDataFlag
     * @param syncNewDataList
     * @return
     */
    @Override
    public boolean updateStateBySyncResult(boolean syncDataFlag, List<SyncNewData> syncNewDataList) {
        if (syncDataFlag) {
            for (SyncNewData syncNewData : syncNewDataList) {
                //数据同步失败,更新跟踪表及日志记录表
                //记录同步追踪表数据 ****************************************************
                String SyncTraceCode = syncTraceSV.saveSyncTrace(syncNewData.getFactoryCode(), SyncTraceState.SyncSuccess.name(),
                        SyncTraceState.DownwardSync.name(), syncNewData.getModel(), syncNewData.getCode(), SyncTraceState.DownwardSync.val + ",数据模型[" + syncNewData.getModel() + "],数据编码-工厂编码[" + syncNewData.getCode() + "-" + syncNewData.getFactoryCode() + "]");
                //记录同步数据日志 ****************************************************
                syncDataTraceSV.saveSyncDataTrace(SyncTraceCode, syncNewData);
                //改变数据同步状态为已同步
                syncNewData.setState(SyncNewDataState.Synced.name());
                syncNewData.setUpdateTime(new Date());
                this.modify(syncNewData);
            }
            return true;
        } else {
            for (SyncNewData syncNewData : syncNewDataList) {
                //数据同步失败,更新跟踪表及日志记录表
                //记录同步追踪表数据 ****************************************************
                String SyncTraceCode = syncTraceSV.saveSyncTrace(syncNewData.getFactoryCode(), SyncTraceState.SyncFailed.name(),
                        SyncTraceState.DownwardSync.name(), syncNewData.getModel(), syncNewData.getCode(), SyncTraceState.DownwardSync.val + ",数据模型[" + syncNewData.getModel() + "],数据编码-工厂编码[" + syncNewData.getCode() + "-" + syncNewData.getFactoryCode() + "]");
                //记录同步数据日志 ****************************************************
                syncDataTraceSV.saveSyncDataTrace(SyncTraceCode, syncNewData);
                //改变数据同步状态为已同步
                syncNewData.setState(SyncNewDataState.Error.name());
                syncNewData.setUpdateTime(new Date());
                this.modify(syncNewData);
            }
            return false;
        }
    }


}
